import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.concurrent.*;

public class MyExecutor  extends AbstractExecutorService {
	
	private ThreadPoolExecutor myThrPoEx;
	protected int maxThreads;
	
	public MyExecutor(){
		super();
	}
	public MyExecutor(long waitTime, long computeTime, BigDecimal targetUtilization){
		
		maxThreads = calculateThreads(waitTime, computeTime,  targetUtilization);
		
		myThrPoEx = new ThreadPoolExecutor(maxThreads, maxThreads,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
		
	
	}
	
	public void execute(Runnable task){
		myThrPoEx.execute(task);
	}

	private int calculateThreads(long wait, long cpu, BigDecimal targetUtilization){
		BigDecimal waitTime = new BigDecimal(wait);
		
		BigDecimal computeTime = new BigDecimal(cpu);
		
		BigDecimal numberOfCPU = new BigDecimal(Runtime.getRuntime().availableProcessors());
		
		BigDecimal optimalthreads = numberOfCPU.multiply(targetUtilization).multiply(
 				new BigDecimal(1).add(waitTime.divide(computeTime, RoundingMode.HALF_UP)));
		
		return optimalthreads.intValue();
	}
	
	public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException{
		
		return myThrPoEx.awaitTermination(timeout, unit);
	}
	
	
	public boolean isShutdown() {
        return myThrPoEx.isShutdown();
    }
	
	public boolean isTerminating() {
        
        return myThrPoEx.isTerminated();
    }
	
	public boolean isTerminated() {
        return myThrPoEx.isTerminated();
    }
	
	public int getPoolSize(){return maxThreads ;}
	
	public void setKeepAliveTime(long time, TimeUnit unit) {
		myThrPoEx.setKeepAliveTime(time, unit);
    }
	
	public long getKeepAliveTime(TimeUnit unit) {
        return myThrPoEx.getKeepAliveTime(unit);
    }
	
	public void shutdown(){
		myThrPoEx.shutdown();
	}
	
	public List<Runnable> shutdownNow(){
		return myThrPoEx.shutdownNow();
	}
	
	public int getActiveCount() {
		return myThrPoEx.getActiveCount();
	}
	
	public void setNumThreads(int nThreads){
		myThrPoEx.setMaximumPoolSize(nThreads);
		myThrPoEx.setCorePoolSize(nThreads);
	}
}
